#pragma once

#include "sock.hpp"
#include <algorithm>
#include <functional>
int max(int a, int b)
{
    return a > b ? a : b;
}
namespace select_cbr
{
    static const int default_port = 8080;
    static const int fd_num = sizeof(fd_set) * 8;
    static const int defaultfd = -1;
    using func = std::function<std::string(const std::string&)>;
    class SelectServer
    {
    public:
        SelectServer(func funct, int port = default_port) : _func(funct), _port(port), _listensock(-1), _fdarray(nullptr)
        {
        }

        void initServer()
        {
            _listensock = Sock::Socket();
            Sock::Bind(_listensock, _port);
            Sock::Listen(_listensock);
            _fdarray = new int[fd_num];
            for (int i = 0; i < fd_num; i++)
                _fdarray[i] = defaultfd;
            _fdarray[0] = _listensock;
        }

        void Accepter(int listensock)
        {
            std::string clientIp;
            uint16_t clientPort;
            int sock = Sock::Accept(listensock, &clientIp, &clientPort);
            if (sock < 0)
                return;
            int i = 0;
            for (; i < fd_num; i++)
            {
                if (_fdarray[i] == defaultfd)
                    break;
            }
            if (i == fd_num)
            {
                close(sock);
            }
            else
            {
                _fdarray[i] = sock;
            }
        }

        void Recver(int sock, int pos)
        {

            char buffer[1024];
            ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
            if (s > 0)
            {
                buffer[s] = 0;
            }
            else if (s == 0)
            {
                close(sock);
                _fdarray[pos] = defaultfd;
                return;
            }
            else
            {
                close(sock);
                _fdarray[pos] = defaultfd;
                return;
            }
            std::string response = _func(buffer);
            write(sock, response.c_str(), response.size());
        }

        void HanderEvent(fd_set& rfds)
        {
            for (int i = 0; i < fd_num; i++)
            {
                if (_fdarray[i] == defaultfd)
                    continue;

                if (FD_ISSET(_fdarray[i], &rfds) && _fdarray[i] == _listensock)
                {
                    Accepter(_listensock);
                }
                else if (FD_ISSET(_fdarray[i], &rfds))
                {
                    Recver(_fdarray[i], i);
                }
            }
        }

        void start()
        {
            int cnt = 1;
            while (1)
            {
                fd_set rfds;
                FD_ZERO(&rfds);
                int maxfd = 0;
                for (int i = 0; i < fd_num; i++)
                {
                    if (_fdarray[i] == defaultfd)
                        continue;
                    FD_SET(_fdarray[i], &rfds);
                    maxfd = max(maxfd, _fdarray[i]);
                }
                // struct timeval timeout = {0, 0};
                int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
                cnt++;
                if (n == -1)
                {
                }
                else if (n == 0)
                {
                }
                else
                {
                    HanderEvent(rfds);
                }
                sleep(1);
            }
        }

        ~SelectServer()
        {
            if (_listensock < 0)
                close(_listensock);
            if (_fdarray)
                delete[] _fdarray;
        }

    private:
        int _port;
        int _listensock;
        int* _fdarray;
        func _func;
    };
}